跳到主要内容
08:08:54
🔅🔆

使用kubeadm在Rocky linux上安装k8s集群

kubeadm安装官方文档

实验环境​

角色IP主机名containerd版本硬件配置系统内核安装组件
master10.0.0.10k8s-master2.0.22c4gRocky Linux release 10.0 (Red Quartz)6.12.0-55.12.1.el10_0kube-apiserver,kube-controller-manager,kube-scheduler,kubelet,etcd
Node0110.0.0.100K8s-node012.0.24c8gRocky Linux release 10.0 (Red Quartz)6.12.0-55.12.1.el10_0kubelet,kube-proxy,containerd,etcd
node0210.0.0.101k8s-node022.0.24c8gRocky Linux release 10.0 (Red Quartz)6.12.0-55.12.1.el10_0kubelet,kube-proxy,containerd,etcd
node0310.0.0.102k8s-node032.0.22c4gRocky Linux release 10.0 (Red Quartz)6.12.0-55.12.1.el10_0kubelet,kube-proxy,containerd,etcd

准备开始​

官方文档

  • 一台兼容的 Linux 主机。Kubernetes 项目为基于 Debian 和 Red Hat 的 Linux 发行版以及一些不提供包管理器的发行版提供通用的指令。
  • 每台机器 2 GB 或更多的 RAM(如果少于这个数字将会影响你应用的运行内存)。
  • CPU 2 核心及以上。
  • 集群中的所有机器的网络彼此均能相互连接(公网和内网都可以)。
  • 节点之中不可以有重复的主机名、MAC 地址或 product_uuid。请参见这里了解更多详细信息。
  • 开启机器上的某些端口。请参见这里了解更多详细信息。
  • 交换分区的配置。kubelet 的默认行为是在节点上检测到交换内存时无法启动。 kubelet 自 v1.22 起已开始支持交换分区。自 v1.28 起,仅针对 cgroup v2 支持交换分区; kubelet 的 NodeSwap 特性门控处于 Beta 阶段,但默认被禁用。
    • 如果 kubelet 未被正确配置使用交换分区,则你必须禁用交换分区。 例如,sudo swapoff -a 将暂时禁用交换分区。要使此更改在重启后保持不变,请确保在如 /etc/fstab、systemd.swap 等配置文件中禁用交换分区,具体取决于你的系统如何配置。
说明

kubeadm 的安装是通过使用动态链接的二进制文件完成的,安装时假设你的目标系统提供 glibc。 这个假设在许多 Linux 发行版(包括 Debian、Ubuntu、Fedora、CentOS 等)上是合理的, 但对于不包含默认 glibc 的自定义和轻量级发行版(如 Alpine Linux),情况并非总是如此。 预期的情况是,发行版要么包含 glibc, 要么提供了一个兼容层以提供所需的符号。

确保每个节点上 MAC 地址和 product_uuid 的唯一性​

官方文档

  • 你可以使用命令 ip link 或 ifconfig -a 来获取网络接口的 MAC 地址
  • 可以使用 sudo cat /sys/class/dmi/id/product_uuid 命令对 product_uuid 校验

一般来讲,硬件设备会拥有唯一的地址,但是有些虚拟机的地址可能会重复。 Kubernetes 使用这些值来唯一确定集群中的节点。 如果这些值在每个节点上不唯一,可能会导致安装失败。

检查网络适配器​

官方文档

如果你有一个以上的网络适配器,同时你的 Kubernetes 组件通过默认路由不可达,我们建议你预先添加 IP 路由规则, 这样 Kubernetes 集群就可以通过对应的适配器完成连接。

检查所需端口​

官方文档

启用这些必要的端口后才能使 Kubernetes 的各组件相互通信。 可以使用 netcat 之类的工具来检查端口是否开放,例如:

nc 127.0.0.1 6443 -v

你使用的 Pod 网络插件 (详见后续章节) 也可能需要开启某些特定端口。 由于各个 Pod 网络插件的功能都有所不同,请参阅他们各自文档中对端口的要求。

master节点需要启用的端口

协议方向端口范围目的使用者
TCP入站6443Kubernetes API 服务器所有
TCP入站2379-2380etcd 服务器客户端 APIkube-apiserver、etcd
TCP入站10250kubelet API自身、控制面
TCP入站10259kube-scheduler自身
TCP入站10257kube-controller-manager自身

node节点需要启用的端口

协议方向端口范围目的使用者
TCP入站10250kubelet API自身、控制面
TCP入站10256kube-proxy自身、负载均衡器
TCP入站30000-32767NodePort Services†所有

安装容器运行时​

官方文档

为了在 Pod 中运行容器,Kubernetes 使用 容器运行时(Container Runtime)。

默认情况下,Kubernetes 使用 容器运行时接口(Container Runtime Interface,CRI) 来与你所选择的容器运行时交互。

如果你不指定运行时,kubeadm 会自动尝试通过扫描已知的端点列表来检测已安装的容器运行时。

如果检测到有多个或者没有容器运行时,kubeadm 将抛出一个错误并要求你指定一个想要使用的运行时。

参阅 容器运行时 以了解更多信息。

说明

Docker Engine 没有实现 CRI, 而这是容器运行时在 Kubernetes 中工作所需要的。 为此,必须安装一个额外的服务 cri-dockerd。 cri-dockerd 是一个基于传统的内置 Docker 引擎支持的项目, 它在 1.24 版本从 kubelet 中移除。

下面的表格包括被支持的操作系统的已知端点。

运行时Unix 域套接字
containerdunix:///var/run/containerd/containerd.sock
CRI-Ounix:///var/run/crio/crio.sock
Docker Engine(使用 cri-dockerd)unix:///var/run/cri-dockerd.sock

容器运行时类型​

containerd

cri-o

docker cri-dockerd

Mirantis Container Runtime

安装和配置先决条件​

官方文档

启用 IPv4 数据包转发​

使用ansible执行
ansible all -m shell -a $'
cat <<EOF > /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF
sysctl --system
'
# 设置所需的 sysctl 参数,参数在重新启动后保持不变
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.ipv4.ip_forward = 1
EOF

# 应用 sysctl 参数而不重新启动
sudo sysctl --system

使用以下命令验证 net.ipv4.ip_forward 是否设置为 1

使用ansible执行
ansible all -m shell -a 'sysctl net.ipv4.ip_forward'
sysctl net.ipv4.ip_forward

cgroup 驱动​

官方文档

在 Linux 上,控制组(CGroup)用于限制分配给进程的资源。

kubelet 和底层容器运行时都需要对接控制组来强制执行 为 Pod 和容器管理资源 并为诸如 CPU、内存这类资源设置请求和限制。若要对接控制组,kubelet 和容器运行时需要使用一个 cgroup 驱动。 关键的一点是 kubelet 和容器运行时需使用相同的 cgroup 驱动并且采用相同的配置。

可用的 cgroup 驱动有两个:

cgroupfs 驱动​

cgroupfs 驱动是 kubelet 中默认的 cgroup 驱动。 当使用 cgroupfs 驱动时, kubelet 和容器运行时将直接对接 cgroup 文件系统来配置 cgroup。

当 systemd 是初始化系统时, 不 推荐使用 cgroupfs 驱动,因为 systemd 期望系统上只有一个 cgroup 管理器。 此外,如果你使用 cgroup v2, 则应用 systemd cgroup 驱动取代 cgroupfs。

systemd cgroup 驱动​

当某个 Linux 系统发行版使用 systemd 作为其初始化系统时,初始化进程会生成并使用一个 root 控制组(cgroup),并充当 cgroup 管理器。

systemd 与 cgroup 集成紧密,并将为每个 systemd 单元分配一个 cgroup。 因此,如果你 systemd 用作初始化系统,同时使用 cgroupfs 驱动,则系统中会存在两个不同的 cgroup 管理器。

同时存在两个 cgroup 管理器将造成系统中针对可用的资源和使用中的资源出现两个视图。某些情况下, 将 kubelet 和容器运行时配置为使用 cgroupfs、但为剩余的进程使用 systemd 的那些节点将在资源压力增大时变得不稳定。

当 systemd 是选定的初始化系统时,缓解这个不稳定问题的方法是针对 kubelet 和容器运行时将 systemd 用作 cgroup 驱动。

要将 systemd 设置为 cgroup 驱动,需编辑 KubeletConfiguration 的 cgroupDriver 选项,并将其设置为 systemd。例如:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
...
cgroupDriver: systemd
说明

从 v1.22 开始,在使用 kubeadm 创建集群时,如果用户没有在 KubeletConfiguration 下设置 cgroupDriver 字段,kubeadm 默认使用 systemd。

在 Kubernetes v1.28 中,启用 KubeletCgroupDriverFromCRI 特性门控结合支持 RuntimeConfig CRI RPC 的容器运行时,kubelet 会自动从运行时检测适当的 Cgroup 驱动程序,并忽略 kubelet 配置中的 cgroupDriver 设置。

如果你将 systemd 配置为 kubelet 的 cgroup 驱动,你也必须将 systemd 配置为容器运行时的 cgroup 驱动。参阅容器运行时文档,了解指示说明。例如:

注意

更改已加入集群的节点的 cgroup 驱动是一项敏感的操作。 如果 kubelet 已经使用某 cgroup 驱动的语义创建了 Pod,更改运行时以使用别的 cgroup 驱动,当为现有 Pod 重新创建 PodSandbox 时会产生错误。 重启 kubelet 也可能无法解决此类问题。

如果你有切实可行的自动化方案,使用其他已更新配置的节点来替换该节点, 或者使用自动化方案来重新安装。

安装containerd​

安装containerd​

查看k8s和containerd版本兼容关系

containerd官方安装文档

注意

从v1.6版本开始,捆绑包 cri-containerd-*.tar.gz 已经被弃用,并且会在v2.0版本删除,这里有 官方说明

下载安装包

使用ansible执行
ansible all -m shell -a '\
CONTAINERD_VERSION=2.1.4; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
wget https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/containerd-${CONTAINERD_VERSION}-linux-${ARCHITECTURE}.tar.gz \
'
export CONTAINERD_VERSION=2.1.4
export ARCHITECTURE=$(
case "$(uname -m)" in
x86_64) echo amd64 ;;
aarch64) echo arm64 ;;
*) echo "unsupported"; exit 1 ;;
esac
)

wget https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/containerd-${CONTAINERD_VERSION}-linux-${ARCHITECTURE}.tar.gz

压缩包内容如下

$ tar tf containerd-${CONTAINERD_VERSION}-linux-${ARCHITECTURE}.tar.gz
bin/
bin/containerd
bin/ctr
bin/containerd-stress
bin/containerd-shim-runc-v2

解压缩

使用ansible执行
ansible all -m shell -a '\
CONTAINERD_VERSION=2.1.4; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
tar Cxzvf /usr/local containerd-${CONTAINERD_VERSION}-linux-${ARCHITECTURE}.tar.gz \
'
tar Cxzvf /usr/local containerd-${CONTAINERD_VERSION}-linux-${ARCHITECTURE}.tar.gz

使用systemd管理containerd

下载文件

使用ansible执行
ansible all -b -m get_url -a "url=https://raw.githubusercontent.com/containerd/containerd/main/containerd.service dest=/usr/lib/systemd/system/containerd.service mode=0644"
curl https://raw.githubusercontent.com/containerd/containerd/main/containerd.service -o /usr/lib/systemd/system/containerd.service

containerd.service 文件内容如下

# Copyright The containerd Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target

[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd

Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999

[Install]
WantedBy=multi-user.target

重新加载 systemd 的配置并设置containerd服务开机自启

使用ansible执行
ansible all -b -m systemd -a "daemon_reload=yes"
ansible all -b -m systemd -a "name=containerd enabled=yes"
systemctl daemon-reload
systemctl enable --now containerd

安装runc​

runc github地址

下载安装包

使用ansible执行
ansible all -m shell -a '\
RUNC_VERSION=1.3.0; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
wget https://github.com/opencontainers/runc/releases/download/v${RUNC_VERSION}/runc.${ARCHITECTURE} \
'
export RUNC_VERSION=1.3.0
export ARCHITECTURE=$(
case "$(uname -m)" in
x86_64) echo amd64 ;;
aarch64) echo arm64 ;;
*) echo "unsupported"; exit 1 ;;
esac
)

wget https://github.com/opencontainers/runc/releases/download/v${RUNC_VERSION}/runc.${ARCHITECTURE}

安装

使用ansible执行
ansible all -m shell -a '\
RUNC_VERSION=1.3.0; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
install -m 755 runc.${ARCHITECTURE} /usr/local/sbin/runc \
'
install -m 755 runc.${ARCHITECTURE} /usr/local/sbin/runc

验证

$ runc -v
runc version 1.3.0
commit: v1.3.0-0-g4ca628d1
spec: 1.2.1
go: go1.23.8
libseccomp: 2.5.6

安装CNI插件​

CNI插件github地址

下载安装包

使用ansible执行
ansible all -m shell -a '\
CNI_VERSION=1.7.1; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
wget https://github.com/containernetworking/plugins/releases/download/v${CNI_VERSION}/cni-plugins-linux-${ARCHITECTURE}-v${CNI_VERSION}.tgz \
'
export CNI_VERSION=1.7.1
export ARCHITECTURE=$(
case "$(uname -m)" in
x86_64) echo amd64 ;;
aarch64) echo arm64 ;;
*) echo "unsupported"; exit 1 ;;
esac
)

wget https://github.com/containernetworking/plugins/releases/download/v${CNI_VERSION}/cni-plugins-linux-${ARCHITECTURE}-v${CNI_VERSION}.tgz

安装包内容如下

$ tar tf cni-plugins-linux-${ARCHITECTURE}-v${CNI_VERSION}.tgz
./
./vrf
./firewall
./LICENSE
./macvlan
./static
./host-device
./host-local
./loopback
./sbr
./tuning
./bridge
./README.md
./ptp
./bandwidth
./vlan
./portmap
./ipvlan
./dummy
./tap
./dhcp

解压缩

使用ansible执行
ansible all -m shell -a '\
CNI_VERSION=1.7.1; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
tar Cxzvf /usr/local/bin cni-plugins-linux-${ARCHITECTURE}-v${CNI_VERSION}.tgz \
'
export CNI_VERSION=1.7.1
export ARCHITECTURE=$(
case "$(uname -m)" in
x86_64) echo amd64 ;;
aarch64) echo arm64 ;;
*) echo "unsupported"; exit 1 ;;
esac
)

tar Cxzvf /usr/local/bin cni-plugins-linux-${ARCHITECTURE}-v${CNI_VERSION}.tgz

配置containerd​

创建containerd配置文件​

官方说明文档

使用ansible执行
ansible all -m shell -a 'mkdir -p /etc/containerd && containerd config default > /etc/containerd/config.toml'
mkdir -p /etc/containerd && containerd config default > /etc/containerd/config.toml

配置 systemd group 驱动​

说明

当 systemd 是初始化系统时, 不 推荐使用 cgroupfs 驱动,因为 systemd 期望系统上只有一个 cgroup 管理器。 此外,如果你使用 cgroup v2, 则应用 systemd cgroup 驱动取代 cgroupfs。

当某个 Linux 系统发行版使用 systemd 作为其初始化系统时,初始化进程会生成并使用一个 root 控制组(cgroup),并充当 cgroup 管理器。

systemd 与 cgroup 集成紧密,并将为每个 systemd 单元分配一个 cgroup。 因此,如果你 systemd 用作初始化系统,同时使用 cgroupfs 驱动,则系统中会存在两个不同的 cgroup 管理器。

同时存在两个 cgroup 管理器将造成系统中针对可用的资源和使用中的资源出现两个视图。某些情况下, 将 kubelet 和容器运行时配置为使用 cgroupfs、但为剩余的进程使用 systemd 的那些节点将在资源压力增大时变得不稳定。

当 systemd 是选定的初始化系统时,缓解这个不稳定问题的方法是针对 kubelet 和容器运行时将 systemd 用作 cgroup 驱动。

containerd2.x版本修改cgroup驱动官方文档

修改 /etc/containerd/config.toml ,在 [plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options] 下新增 SystemdCgroup = true

使用ansible执行
ansible all -b -m lineinfile -a "path=/etc/containerd/config.toml insertafter=\"ShimCgroup = ''\" line=' SystemdCgroup = true' backup=yes"
version = 3
[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
SystemdCgroup = true

使用sed修改

sed -i.bak "/\[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options\]/a \ \ \ \ \ \ \ \ \ \ \ \ SystemdCgroup = true" /etc/containerd/config.toml

修改 pause 镜像地址​

说明

在 /etc/containerd/config.toml 配置文件中,pause镜像的默认地址是 registry.k8s.io/pause:3.10,由于某些特殊原因,需要修改这个镜像的地址,可以使用ucloud提供的加速地址

uhub.service.ucloud.cn/996.icu/pause:3.10 或者阿里云提供的加速地址 registry.aliyuncs.com/k8sxio/pause:3.10

修改 registry.k8s.io 为 registry.aliyuncs.com/google_containers

[plugins.'io.containerd.cri.v1.images'.pinned_images]
sandbox = 'registry.aliyuncs.com/google_containers/pause:3.10'

用如下命令修改

使用ansible执行
ansible all -b -m replace -a "path=/etc/containerd/config.toml regexp='registry.k8s.io/pause:3.10' replace='registry.aliyuncs.com/google_containers/pause:3.10'"
sed -i 's#registry.k8s.io#registry.aliyuncs.com/google_containers#' /etc/containerd/config.toml

配置containerd镜像仓库加速​

containerd镜像仓库配置官方文档

阿里云官方文档

修改配置文件​

修改 /etc/containerd/config.toml ,修改 config_path ,新增 /etc/containerd/certs.d

[plugins.'io.containerd.cri.v1.images'.registry]
config_path = '/etc/containerd/certs.d'

使用如下命令修改

sed -i "/\[plugins.'io.containerd.cri.v1.images'.registry\]/a \ \ \ \ \ \ config_path = '/etc/containerd/certs.d'" /etc/containerd/config.toml && sed -i "/config_path = ''/d" /etc/containerd/config.toml
重启containerd​
使用ansible执行
ansible all -b -m systemd -a "name=containerd state=restarted"
systemctl restart containerd
创建目录​
使用ansible执行
ansible all -b -m file -a "path=/etc/containerd/certs.d/docker.io state=directory mode=0755"
mkdir -p /etc/containerd/certs.d/docker.io
创建 hosts.toml 文件并写入以下内容​
使用ansible执行
ansible all -b -m copy -a "content='server = \"https://registry-1.docker.io\"\n\n[host.\"https://bqr1dr1n.mirror.aliyuncs.com\"]\n capabilities = [\"pull\", \"resolve\", \"push\"]' dest=/etc/containerd/certs.d/docker.io/hosts.toml"
cat > /etc/containerd/certs.d/docker.io/hosts.toml << 'EOF'
server = "https://registry-1.docker.io"

[host."https://bqr1dr1n.mirror.aliyuncs.com"]
capabilities = ["pull", "resolve", "push"]
EOF
验证镜像下载加速​
说明

使用 ctr 命令验证下载加速需要手动指定 --hosts-dir

使用 --debug=true 可以查看具体信息,其中 DEBU[0000] resolving host=bqr1dr1n.mirror.aliyuncs.com 信息就表明下载加速走的是配置的地址

$ ctr -n k8s.io --debug=true i pull --hosts-dir=/etc/containerd/certs.d docker.io/library/centos:centos7.9.2009
DEBU[0000] fetching image="docker.io/library/centos:centos7.9.2009"
DEBU[0000] loading host directory dir=/etc/containerd/certs.d/docker.io
DEBU[0000] resolving host=bqr1dr1n.mirror.aliyuncs.com
DEBU[0000] do request host=bqr1dr1n.mirror.aliyuncs.com request.header.accept="application/vnd.docker.distribution.manifest.v2+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, */*" request.header.user-agent=containerd/v1.7.17 request.method=HEAD url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/manifests/centos7.9.2009?ns=docker.io"
DEBU[0015] fetch response received host=bqr1dr1n.mirror.aliyuncs.com response.header.content-length=1199 response.header.content-type=application/vnd.docker.distribution.manifest.list.v2+json response.header.date="Fri, 24 May 2024 12:37:17 GMT" response.header.docker-content-digest="sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987" response.header.docker-distribution-api-version=registry/2.0 response.header.etag="\"sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987\"" response.status="200 OK" url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/manifests/centos7.9.2009?ns=docker.io"
DEBU[0015] resolved desc.digest="sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987" host=bqr1dr1n.mirror.aliyuncs.com
DEBU[0015] loading host directory dir=/etc/containerd/certs.d/docker.io
DEBU[0015] fetch digest="sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987" mediatype=application/vnd.docker.distribution.manifest.list.v2+json size=1199
DEBU[0015] do request digest="sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987" mediatype=application/vnd.docker.distribution.manifest.list.v2+json request.header.accept="application/vnd.docker.distribution.manifest.list.v2+json, */*" request.header.user-agent=containerd/v1.7.17 request.method=GET size=1199 url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/manifests/sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987?ns=docker.io"
DEBU[0016] fetch response received digest="sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987" mediatype=application/vnd.docker.distribution.manifest.list.v2+json response.header.content-length=1199 response.header.content-type=application/vnd.docker.distribution.manifest.list.v2+json response.header.date="Fri, 24 May 2024 12:37:18 GMT" response.header.docker-content-digest="sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987" response.header.docker-distribution-api-version=registry/2.0 response.header.etag="\"sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987\"" response.status="200 OK" size=1199 url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/manifests/sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987?ns=docker.io"
DEBU[0016] fetch digest="sha256:864a7acea4a5e8fa7a4d83720fbcbadbe38b183f46f3600e04a3f8c1d961ed87" mediatype=application/vnd.docker.distribution.manifest.v2+json size=530
DEBU[0016] do request digest="sha256:864a7acea4a5e8fa7a4d83720fbcbadbe38b183f46f3600e04a3f8c1d961ed87" mediatype=application/vnd.docker.distribution.manifest.v2+json request.header.accept="application/vnd.docker.distribution.manifest.v2+json, */*" request.header.user-agent=containerd/v1.7.17 request.method=GET size=530 url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/manifests/sha256:864a7acea4a5e8fa7a4d83720fbcbadbe38b183f46f3600e04a3f8c1d961ed87?ns=docker.io"
DEBU[0016] fetch response received digest="sha256:864a7acea4a5e8fa7a4d83720fbcbadbe38b183f46f3600e04a3f8c1d961ed87" mediatype=application/vnd.docker.distribution.manifest.v2+json response.header.content-length=530 response.header.content-type=application/vnd.docker.distribution.manifest.v2+json response.header.date="Fri, 24 May 2024 12:37:18 GMT" response.header.docker-content-digest="sha256:864a7acea4a5e8fa7a4d83720fbcbadbe38b183f46f3600e04a3f8c1d961ed87" response.header.docker-distribution-api-version=registry/2.0 response.header.etag="\"sha256:864a7acea4a5e8fa7a4d83720fbcbadbe38b183f46f3600e04a3f8c1d961ed87\"" response.status="200 OK" size=530 url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/manifests/sha256:864a7acea4a5e8fa7a4d83720fbcbadbe38b183f46f3600e04a3f8c1d961ed87?ns=docker.io"
DEBU[0016] fetch digest="sha256:6717b8ec66cd6add0272c6391165585613c31314a43ff77d9751b53010e531ec" mediatype=application/vnd.docker.image.rootfs.diff.tar.gzip size=108374945
DEBU[0016] fetch digest="sha256:dfc30428e1631ce2adb2a7978c667f88dc033a3c2991943f5e2307d857ed0370" mediatype=application/vnd.docker.container.image.v1+json size=2770
DEBU[0016] do request digest="sha256:dfc30428e1631ce2adb2a7978c667f88dc033a3c2991943f5e2307d857ed0370" mediatype=application/vnd.docker.container.image.v1+json request.header.accept="application/vnd.docker.container.image.v1+json, */*" request.header.user-agent=containerd/v1.7.17 request.method=GET size=2770 url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/blobs/sha256:dfc30428e1631ce2adb2a7978c667f88dc033a3c2991943f5e2307d857ed0370?ns=docker.io"
DEBU[0016] do request digest="sha256:6717b8ec66cd6add0272c6391165585613c31314a43ff77d9751b53010e531ec" mediatype=application/vnd.docker.image.rootfs.diff.tar.gzip request.header.accept="application/vnd.docker.image.rootfs.diff.tar.gzip, */*" request.header.user-agent=containerd/v1.7.17 request.method=GET size=108374945 url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/blobs/sha256:6717b8ec66cd6add0272c6391165585613c31314a43ff77d9751b53010e531ec?ns=docker.io"
DEBU[0018] fetch response received digest="sha256:dfc30428e1631ce2adb2a7978c667f88dc033a3c2991943f5e2307d857ed0370" mediatype=application/vnd.docker.container.image.v1+json response.header.accept-ranges=bytes response.header.connection=keep-alive response.header.content-length=2770 response.header.content-type=application/octet-stream response.header.date="Fri, 24 May 2024 12:37:20 GMT" response.header.etag="\"858C8D660CF7A6AD53DD55B2FF6A70CC-1\"" response.header.last-modified="Thu, 16 Sep 2021 04:27:31 GMT" response.header.server=AliyunOSS response.header.x-oss-hash-crc64ecma=17094106414512831035 response.header.x-oss-object-type=Multipart response.header.x-oss-request-id=66508A00EAC5D23836F0034C response.header.x-oss-server-time=132 response.header.x-oss-storage-class=Standard response.status="200 OK" size=2770 url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/blobs/sha256:dfc30428e1631ce2adb2a7978c667f88dc033a3c2991943f5e2307d857ed0370?ns=docker.io"
DEBU[0018] fetch response received digest="sha256:6717b8ec66cd6add0272c6391165585613c31314a43ff77d9751b53010e531ec" mediatype=application/vnd.docker.image.rootfs.diff.tar.gzip response.header.accept-ranges=bytes response.header.connection=keep-alive response.header.content-length=108374945 response.header.content-type=application/octet-stream response.header.date="Fri, 24 May 2024 12:37:20 GMT" response.header.etag="\"76ADAA83857B8D1557F847298BECEEA8-10\"" response.header.last-modified="Sun, 15 Nov 2020 06:09:39 GMT" response.header.server=AliyunOSS response.header.x-oss-hash-crc64ecma=10643295449866978854 response.header.x-oss-object-type=Multipart response.header.x-oss-request-id=66508A006F20953038FEEC41 response.header.x-oss-server-time=175 response.header.x-oss-storage-class=Standard response.status="200 OK" size=108374945 url="https://bqr1dr1n.mirror.aliyuncs.com/v2/library/centos/blobs/sha256:6717b8ec66cd6add0272c6391165585613c31314a43ff77d9751b53010e531ec?ns=docker.io"
DEBU[0317] unpacking image="docker.io/library/centos:centos7.9.2009"
unpacking linux/arm64/v8 sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987...
done: 1.495863023s

安装其他工具​

安装cri-tools(可选)​

cri-tools github地址

cri-tools官方文档

下载安装包

使用ansible执行
ansible all -m shell -a '\
CRICTL_VERSION=1.33.0; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v${CRICTL_VERSION}/crictl-v${CRICTL_VERSION}-linux-${ARCHITECTURE}.tar.gz \
'
export CRICTL_VERSION=1.33.0
export ARCHITECTURE=$(
case "$(uname -m)" in
x86_64) echo amd64 ;;
aarch64) echo arm64 ;;
*) echo "unsupported"; exit 1 ;;
esac
)

wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v${CRICTL_VERSION}/crictl-v${CRICTL_VERSION}-linux-${ARCHITECTURE}.tar.gz

解压缩

使用ansible执行
ansible all -m shell -a '\
CRICTL_VERSION=1.33.0; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
tar Cxzvf /usr/local/bin crictl-v${CRICTL_VERSION}-linux-${ARCHITECTURE}.tar.gz \
'
tar Cxzvf /usr/local/bin crictl-v${CRICTL_VERSION}-linux-${ARCHITECTURE}.tar.gz

执行命令有警告

$ crictl images
WARN[0000] image connect using default endpoints: [unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.

解决方法

因为使用的是containerd,因此需要将容器运行时修改为containerd,修改完成后就可以成功执行命令了

使用ansible执行
ansible all -m shell -a "crictl config --set runtime-endpoint=unix:///run/containerd/containerd.sock --set image-endpoint=unix:///run/containerd/containerd.sock"
crictl config --set runtime-endpoint=unix:///run/containerd/containerd.sock --set image-endpoint=unix:///run/containerd/containerd.sock

/etc/crictl.yaml 文件内容最终如下

$ cat /etc/crictl.yaml
runtime-endpoint: "unix:///run/containerd/containerd.sock"
image-endpoint: "unix:///run/containerd/containerd.sock"
timeout: 0
debug: false
pull-image-on-create: false
disable-pull-on-run: false

配置 crictl 命令补全

使用ansible执行
ansible all -b -m lineinfile -a "path=~/.bashrc line='source <(crictl completion bash)' state=present"
echo "source <(crictl completion bash)" >> ~/.bashrc
source ~/.bashrc

安装nerdctl(可选)​

nerdctl github地址

说明

nerdctl 是一个适用于containerd的dcoker兼容CLI

安装containerd后需要使用 ctr 命令管理操作容器,但是操作命令与docker相差比较大, nerdctl 就很好的解决了这个问题,既能在使用containerd的同时又能使用原先docker命令的用法

下载安装包

说明

如果没有安装 containerd,则可以下载 nerdctl-full-\<VERSION>-linux-<ARCHITECTURE>.tar.gz 包进行安装,并且 nerdctl-full 这个包是与containerd版本一一对应的,即containerd发布一个版本后,nerdctl-full 也随即发布一个版本,虽然2者版本号不一致,但是是互相对应的

使用ansible执行
ansible all -m shell -a '\
NERDCTL_VERSION=2.1.3; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
wget https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-${ARCHITECTURE}.tar.gz \
'
export NERDCTL_VERSION=2.1.3
export ARCHITECTURE=$(
case "$(uname -m)" in
x86_64) echo amd64 ;;
aarch64) echo arm64 ;;
*) echo "unsupported"; exit 1 ;;
esac
)

wget https://github.com/containerd/nerdctl/releases/download/v${NERDCTL_VERSION}/nerdctl-${NERDCTL_VERSION}-linux-${ARCHITECTURE}.tar.gz

解压缩

说明

压缩包内容为 nerdctl 命令以及 containerd-rootless-setuptool.sh 和 containerd-rootless.sh ,均有执行权限

$ tar tf nerdctl-${NERDCTL_VERSION}-linux-${ARCHITECTURE}.tar.gz
nerdctl
containerd-rootless-setuptool.sh
containerd-rootless.sh
使用ansible执行
ansible all -m shell -a '\
NERDCTL_VERSION=2.1.3; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
tar xf nerdctl-${NERDCTL_VERSION}-linux-${ARCHITECTURE}.tar.gz \
'
tar xf nerdctl-${NERDCTL_VERSION}-linux-${ARCHITECTURE}.tar.gz

拷贝二进制文件

使用ansible执行
ansible all -m shell -a 'mv nerdctl /usr/local/bin'
mv nerdctl /usr/local/bin

配置 nerdctl 命令补全

使用ansible执行
ansible all -b -m lineinfile -a "path=~/.bashrc line='source <(nerdctl completion bash)' state=present"
echo "source <(nerdctl completion bash)" >> ~/.bashrc
source ~/.bashrc
安装nerdctl其他组件​
CNI plugins CNI 插件 ​

此插件用于执行 nerdctl run 命令,强烈建议使用 v1.1.0 或更高版本。旧版本需要额外的 CNI 隔离插件来隔离桥接网络

BuildKit 构建套件 (可选)​

此插件用于执行 nerdctl build ,强烈建议使用 v0.11.0 或更高版本。某些功能(例如使用 nerdctl system prune)不适用于旧版本。

BuildKit 守护程序需要运行,参考 有关设置 BuildKit 的文档 ,否则运行 nerdctl build 会报错如下

$ nerdctl build
ERRO[0000] `buildctl` needs to be installed and `buildkitd` needs to be running, see https://github.com/moby/buildkit error="failed to ping to host unix:///run/buildkit-default/buildkitd.sock: exec: \"buildctl\": executable file not found in $PATH\nfailed to ping to host unix:///run/buildkit/buildkitd.sock: exec: \"buildctl\": executable file not found in $PATH"
FATA[0000] no buildkit host is available, tried 2 candidates: failed to ping to host unix:///run/buildkit-default/buildkitd.sock: exec: "buildctl": executable file not found in $PATH
failed to ping to host unix:///run/buildkit/buildkitd.sock: exec: "buildctl": executable file not found in $PATH

下载安装包

使用ansible执行
ansible all -m shell -a '\
BUILDKIT_VERSION=0.23.2; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
wget https://github.com/moby/buildkit/releases/download/v${BUILDKIT_VERSION}/buildkit-v${BUILDKIT_VERSION}.linux-${ARCHITECTURE}.tar.gz \
'
export BUILDKIT_VERSION=0.23.2
export ARCHITECTURE=$(
case "$(uname -m)" in
x86_64) echo amd64 ;;
aarch64) echo arm64 ;;
*) echo "unsupported"; exit 1 ;;
esac
)

wget https://github.com/moby/buildkit/releases/download/v${BUILDKIT_VERSION}/buildkit-v${BUILDKIT_VERSION}.linux-${ARCHITECTURE}.tar.gz

解压缩

说明

压缩包内容如下

$ tar tf buildkit-v${BUILDKIT_VERSION}.linux-${ARCHITECTURE}.tar.gz
bin/
bin/buildctl
bin/buildkit-cni-bridge
bin/buildkit-cni-firewall
bin/buildkit-cni-host-local
bin/buildkit-cni-loopback
bin/buildkit-qemu-arm
bin/buildkit-qemu-i386
bin/buildkit-qemu-mips64
bin/buildkit-qemu-mips64el
bin/buildkit-qemu-ppc64le
bin/buildkit-qemu-riscv64
bin/buildkit-qemu-s390x
bin/buildkit-qemu-x86_64
bin/buildkit-runc
bin/buildkitd
使用ansible执行
ansible all -m shell -a '\
BUILDKIT_VERSION=0.23.2; \
ARCH=$(uname -m); \
if [ "$ARCH" = "x86_64" ]; then ARCHITECTURE=amd64; \
elif [ "$ARCH" = "aarch64" ]; then ARCHITECTURE=arm64; \
else echo "Unsupported architecture: $ARCH" && exit 1; fi; \
tar xf buildkit-v${BUILDKIT_VERSION}.linux-${ARCHITECTURE}.tar.gz \
'
tar xf buildkit-v${BUILDKIT_VERSION}.linux-${ARCHITECTURE}.tar.gz

拷贝命令

使用ansible执行
ansible all -m shell -a 'cp bin/{buildkitd,buildctl} /usr/local/bin'
cp bin/buildkitd /usr/local/bin
cp bin/buildctl /usr/local/bin

使用systemd管理buildkit进程

使用ansible执行
ansible all -b -m copy -a "dest=/etc/systemd/system/buildkitd.service content='[Unit]\nDescription=Buildkit Daemon\nAfter=network.target\n\n[Service]\nExecStart=/usr/local/bin/buildkitd --addr unix:///run/buildkit/buildkitd.sock\nUser=root\nRestart=always\n\n[Install]\nWantedBy=multi-user.target\n'"
cat > /etc/systemd/system/buildkitd.service << EOF
[Unit]
Description=Buildkit Daemon
After=network.target

[Service]
ExecStart=`which buildkitd` --addr unix:///run/buildkit/buildkitd.sock
User=root
Restart=always

[Install]
WantedBy=multi-user.target
EOF

启动 buildkitd

使用ansible执行
ansible all -b -m systemd -a "name=buildkitd state=started enabled=yes daemon_reload=yes"
systemctl daemon-reload && systemctl start buildkitd.service && systemctl enable buildkitd.service

buildkitd 启动成功后就可以执行 nerdctl build 命令了

RootlessKit and slirp4netns (可选)​

RootlessKit 需要是 v0.10.0 或更高版本。推荐v0.14.1或更高版本。

slirp4netns 需要是 v0.4.0 或更高版本。推荐v1.1.7或更高版本。

此插件用于 rootless 模式,可以参考docker官方对rootless模式的说明

说明

以上3个插件包含在 nerdctl-full-<VERSION>-<OS>-<ARCH>.tar.gz 中,但不包含在 nerdctl-<VERSION>-<OS>-<ARCH>.tar.gz 中

docker和containerd常用命令对比​

命令dockercrictlnerdctlctr
查看容器列表docker pscrictl psnerdctl psctr -n k8s.io c ls
查看容器详情docker inspectcrictl inspectnerdctl inspectctr -n k8s.io c info
查看容器日志docker logscrictl logsnerdctl logs无
容器内执行命令docker execcrictl execnerdctl exec无
挂载容器docker attachcrictl attachnerdctl attach无
显示容器资源使用情况docker statscrictl statsnerdctl stats无
创建容器docker createcrictl createnerdctl createctr -n k8s.io c create
启动容器docker startcrictl startnerdctl startctr -n k8s.io run
停止容器docker stopcrictl stopnerdctl stop无
删除容器docker rmcrictl rmnerdctl rmctr -n k8s.io c del
查看镜像列表docker imagescrictl imagesnerdctl imagesctr -n k8s.io i ls
查看镜像详情docker inspectcrictl inspectinerdctl inspect无
拉取镜像docker pullcrictl pullnerdctl pullctr -n k8s.io i pull
推送镜像docker push无nerdctl pushctr -n k8s.io i push
删除镜像docker rmicrictl rminerdctl rmictr -n k8s.io i rm
查看Pod列表无crictl pods无无
查看Pod详情无crictl inspectp无无
启动Pod无crictl runp无无
停止Pod无crictl stop无无

安装kubeadm、kubelet、kubectl​

配置yum源​

官方文档

使用ansible执行
ansible all -b -m copy -a "dest=/etc/yum.repos.d/kubernetes.repo content='[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni'"
export VERSION=1.33
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v$VERSION/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v$VERSION/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF

安装 kubelet、kubeadm 和 kubectl,并启用 kubelet 以确保它在启动时自动启动​

查看可安装的版本

yum list kubeadm --showduplicates

指定安装版本

export K8S_VERSION=1.33.3
yum -y install kubelet-${K8S_VERSION} kubeadm-${K8S_VERSION} kubectl-${K8S_VERSION} --disableexcludes=kubernetes
systemctl enable --now kubelet

安装最新版

使用ansible执行
# 安装 kubelet、kubeadm、kubectl
ansible all -b -m yum -a "name='kubelet,kubeadm,kubectl' state=present disable_excludes='kubernetes'"

# 启动并开机自启 kubelet
ansible all -b -m systemd -a "name=kubelet enabled=yes state=started"
yum -y install kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet

设置 kubectl 命令补全​

说明

如果做了 kubectl 命令的别名 k ,则还需要添加如下配置才可以使 k 像 kubectl 一样的命令补全功能

使用ansible执行
ansible all -b -m lineinfile -a "path=~/.bashrc line='alias k=kubectl' state=present"
ansible all -b -m lineinfile -a "path=~/.bashrc line='complete -o default -F __start_kubectl k' state=present"
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -o default -F __start_kubectl k' >> ~/.bashrc

:::

使用ansible执行
# 安装 bash-completion
ansible all -b -m yum -a "name=bash-completion state=present"

# 给 root 用户的 bashrc 添加 kubectl 自动补全
ansible all -b -m lineinfile -a "path=~/.bashrc line='source <(kubectl completion bash)' state=present"
yum -y install bash-completion
echo "source <(kubectl completion bash)" >> ~/.bashrc && source ~/.bashrc

使用kubeadm创建集群​

官方文档

初始化master节点​

可执行 kubeadm config print init-defaults 查看默认配置

$ kubeadm config print init-defaults
apiVersion: kubeadm.k8s.io/v1beta4
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 1.2.3.4
bindPort: 6443
nodeRegistration:
criSocket: unix:///var/run/containerd/containerd.sock
imagePullPolicy: IfNotPresent
imagePullSerial: true
name: node
taints: null
timeouts:
controlPlaneComponentHealthCheck: 4m0s
discovery: 5m0s
etcdAPICall: 2m0s
kubeletHealthCheck: 4m0s
kubernetesAPICall: 1m0s
tlsBootstrap: 5m0s
upgradeManifests: 5m0s
---
apiServer: {}
apiVersion: kubeadm.k8s.io/v1beta4
caCertificateValidityPeriod: 87600h0m0s
certificateValidityPeriod: 8760h0m0s
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
encryptionAlgorithm: RSA-2048
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.k8s.io
kind: ClusterConfiguration
kubernetesVersion: 1.31.0
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
proxy: {}
scheduler: {}

初始化方式​

配置文件方式​
说明

初始化方式有命令行和配置文件方式2种

配置文件方式可以参考 官方说明文档(b1beta4)

apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
bootstrapTokens:
- token: "9a08jv.c0izixklcxtmnze7"
description: "kubeadm bootstrap token"
ttl: "24h"
- token: "783bde.3f89s0fje9f38fhf"
description: "another bootstrap token"
usages:
- authentication
- signing
groups:
- system:bootstrappers:kubeadm:default-node-token
nodeRegistration:
name: "ec2-10-100-0-1"
criSocket: "unix:///var/run/containerd/containerd.sock"
taints:
- key: "kubeadmNode"
value: "someValue"
effect: "NoSchedule"
kubeletExtraArgs:
- name: "v"
value: "5"
ignorePreflightErrors:
- IsPrivilegedUser
imagePullPolicy: "IfNotPresent"
imagePullSerial: true
localAPIEndpoint:
advertiseAddress: "10.100.0.1"
bindPort: 6443
certificateKey: "e6a2eb8581237ab72a4f494f30285ec12a9694d750b9785706a83bfcbbbd2204"
skipPhases:
- preflight
timeouts:
controlPlaneComponentHealthCheck: "60s"
kubernetesAPICall: "40s"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
etcd:
# one of local or external
local:
imageRepository: "registry.k8s.io"
imageTag: "3.2.24"
dataDir: "/var/lib/etcd"
extraArgs:
- name: "listen-client-urls"
value: "http://10.100.0.1:2379"
extraEnvs:
- name: "SOME_VAR"
value: "SOME_VALUE"
serverCertSANs:
- "ec2-10-100-0-1.compute-1.amazonaws.com"
peerCertSANs:
- "10.100.0.1"
# external:
# endpoints:
# - "10.100.0.1:2379"
# - "10.100.0.2:2379"
# caFile: "/etcd/kubernetes/pki/etcd/etcd-ca.crt"
# certFile: "/etcd/kubernetes/pki/etcd/etcd.crt"
# keyFile: "/etcd/kubernetes/pki/etcd/etcd.key"
networking:
serviceSubnet: "10.96.0.0/16"
podSubnet: "10.244.0.0/24"
dnsDomain: "cluster.local"
kubernetesVersion: "v1.21.0"
controlPlaneEndpoint: "10.100.0.1:6443"
apiServer:
extraArgs:
- name: "authorization-mode"
value: "Node,RBAC"
extraEnvs:
- name: "SOME_VAR"
value: "SOME_VALUE"
extraVolumes:
- name: "some-volume"
hostPath: "/etc/some-path"
mountPath: "/etc/some-pod-path"
readOnly: false
pathType: File
certSANs:
- "10.100.1.1"
- "ec2-10-100-0-1.compute-1.amazonaws.com"
controllerManager:
extraArgs:
- name: "node-cidr-mask-size"
value: "20"
extraVolumes:
- name: "some-volume"
hostPath: "/etc/some-path"
mountPath: "/etc/some-pod-path"
readOnly: false
pathType: File
scheduler:
extraArgs:
- name: "address"
value: "10.100.0.1"
extraVolumes:
- name: "some-volume"
hostPath: "/etc/some-path"
mountPath: "/etc/some-pod-path"
readOnly: false
pathType: File
certificatesDir: "/etc/kubernetes/pki"
imageRepository: "registry.k8s.io"
clusterName: "example-cluster"
encryptionAlgorithm: "ECDSA-P256"
dns:
disabled: true # disable CoreDNS
proxy:
disabled: true # disable kube-proxy
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
# kubelet specific options here
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
# kube-proxy specific options here

指定配置文件方式

kubeadm init --config kubeadm.yaml

kubeadm.yaml 文件内容

apiVersion: kubeadm.k8s.io/v1beta4
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 10.0.0.10 # 指定master节点内网IP
bindPort: 6443
nodeRegistration:
criSocket: unix:///run/containerd/containerd.sock # 使用 containerd 的 Unix socket 地址
imagePullPolicy: IfNotPresent
name: k8s-master01 # master节点主机名
taints: # 给master添加污点,master节点不能调度应用
- effect: "NoSchedule"
key: "node-role.kubernetes.io/master"

---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs # kube-proxy 模式

---
apiServer:
#timeoutForControlPlane: 4m0s
#Timeouts.ControlPlaneComponentHealthCheck: 4m0s
apiVersion: kubeadm.k8s.io/v1beta4
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: 1.33.3
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
podSubnet: 10.244.0.0/16 # 指定 pod 子网
scheduler: {}

---
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
anonymous:
enabled: false
webhook:
cacheTTL: 0s
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
webhook:
cacheAuthorizedTTL: 0s
cacheUnauthorizedTTL: 0s
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
cpuManagerReconcilePeriod: 0s
evictionPressureTransitionPeriod: 0s
fileCheckFrequency: 0s
healthzBindAddress: 127.0.0.1
healthzPort: 10248
httpCheckFrequency: 0s
imageMinimumGCAge: 0s
kind: KubeletConfiguration
cgroupDriver: systemd # 配置 cgroup driver
logging: {}
memorySwap: {}
nodeStatusReportFrequency: 0s
nodeStatusUpdateFrequency: 0s
rotateCertificates: true
runtimeRequestTimeout: 0s
shutdownGracePeriod: 0s
shutdownGracePeriodCriticalPods: 0s
staticPodPath: /etc/kubernetes/manifests
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
命令行方式​
说明

初始化前也可以执行 kubeadm config images pull 把需要的镜像先拉取下来

kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers

命令行方式

kubeadm init \
--apiserver-advertise-address=10.0.0.12 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.33.3 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=10.244.0.0/16

完整输出如下

[init] Using Kubernetes version: v1.33.3
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action beforehand using 'kubeadm config images pull'
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [k8s-master01 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.0.0.20]
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [k8s-master01 localhost] and IPs [10.0.0.20 127.0.0.1 ::1]
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [k8s-master01 localhost] and IPs [10.0.0.20 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "super-admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests"
[kubelet-check] Waiting for a healthy kubelet at http://127.0.0.1:10248/healthz. This can take up to 4m0s
[kubelet-check] The kubelet is healthy after 1.002491732s
[control-plane-check] Waiting for healthy control plane components. This can take up to 4m0s
[control-plane-check] Checking kube-apiserver at https://10.0.0.20:6443/livez
[control-plane-check] Checking kube-controller-manager at https://127.0.0.1:10257/healthz
[control-plane-check] Checking kube-scheduler at https://127.0.0.1:10259/livez
[control-plane-check] kube-controller-manager is healthy after 2.315389204s
[control-plane-check] kube-scheduler is healthy after 3.914227531s
[control-plane-check] kube-apiserver is healthy after 5.503354225s
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --upload-certs
[mark-control-plane] Marking the node k8s-master01 as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers]
[mark-control-plane] Marking the node k8s-master01 as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: abcdef.0123456789abcdef
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes
[bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
[kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.0.0.20:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:976dee883d1f3cd7b65dee012e0f2b6a42f451f852cf5e7ce1ac6053a7a5f3df

kubeadm init 选项​

官方文档

选项说明
--apiserver-advertise-address stringAPI 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认网络接口。
--apiserver-bind-port int32API 服务器绑定的端口。默认值:6443
--apiserver-cert-extra-sans strings用于 API Server 服务证书的可选附加主题备用名称(SAN)。可以是 IP 地址和 DNS 名称。
--cert-dir string保存和存储证书的路径。默认值 /etc/kubernetes/pki
--certificate-key string用于加密 kubeadm-certs Secret 中的控制平面证书的密钥。
--config stringkubeadm 配置文件的路径。
--control-plane-endpoint string为控制平面指定一个稳定的 IP 地址或 DNS 名称。
--cri-socket string要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值; 仅当安装了多个 CRI 或具有非标准 CRI 套接字时,才使用此选项。
--dry-run不做任何更改;只输出将要执行的操作。
--feature-gates string一组用来描述各种功能特性的键值(key=value)对。选项是:EtcdLearnerMode=true PublicKeysECDSA=true RootlessControlPlane=true UpgradeAddonsBeforeControlPlane=true
-h, --helpinit 操作的帮助命令。
--ignore-preflight-errors strings错误将显示为警告的检查列表;例如:IsPrivilegedUser,Swap。取值为 all 时将忽略检查中的所有错误。
--image-repository string选择用于拉取控制平面镜像的容器仓库。默认值registry.k8s.io
--kubernetes-version string为控制平面选择一个特定的 Kubernetes 版本。默认值:stable-1
--node-name string指定节点的名称。
--patches string它包含名为 target[suffix][+patchtype].extension 的文件的目录的路径。 例如,kube-apiserver0+merge.yaml或仅仅是 etcd.json。 target 可以是 kube-apiserver、kube-controller-manager、kube-scheduler、etcd、kubeletconfiguration 之一。 patchtype 可以是 strategic、merge 或者 json 之一, 并且它们与 kubectl 支持的补丁格式相同。 默认
的 patchtype 是 strategic。 extension 必须是json 或yaml。 suffix 是一个可选字符串,可用于确定首先按字母顺序应用哪些补丁。
--pod-network-cidr string指明 Pod 网络可以使用的 IP 地址段。如果设置了这个参数,控制平面将会为每一个节点自动分配 CIDR。
--service-cidr string为服务的虚拟 IP 地址另外指定 IP 地址段。默认值:10.96.0.0/12
--service-dns-domain string为服务另外指定域名,例如:myorg.internal。 默认值:cluster.local
--skip-certificate-key-print不要打印用于加密控制平面证书的密钥。
--skip-phases strings要跳过的阶段列表。
--skip-token-print跳过打印 kubeadm init 生成的默认引导令牌。
--token string这个令牌用于建立控制平面节点与工作节点间的双向通信。 格式为 [a-z0-9]{6}.[a-z0-9]{16} - 示例:abcdef.0123456789abcdef
--token-ttl duration令牌被自动删除之前的持续时间(例如 1s,2m,3h)。如果设置为 0,则令牌将永不过期。
--upload-certs将控制平面证书上传到 kubeadm-certs Secret。

Init 命令的工作流程

1.在做出变更前运行一系列的预检项来验证系统状态。一些检查项目仅仅触发警告, 其它的则会被视为错误并且退出 kubeadm,除非问题得到解决或者用户指定了 --ignore-preflight-errors=<错误列表> 参数。

2.生成一个自签名的 CA 证书来为集群中的每一个组件建立身份标识。 用户可以通过将其放入 --cert-dir 配置的证书目录中(默认为 /etc/kubernetes/pki) 来提供他们自己的 CA 证书以及/或者密钥。 APIServer 证书将为任何 --apiserver-cert-extra-sans 参数值提供附加的 SAN 条目,必要时将其小写。

3.将 kubeconfig 文件写入 /etc/kubernetes/ 目录以便 kubelet、控制器管理器和调度器用来连接到 API 服务器,它们每一个都有自己的身份标识,同时生成一个名为 admin.conf 的独立的 kubeconfig 文件,用于管理操作。

4.为 API 服务器、控制器管理器和调度器生成静态 Pod 的清单文件。假使没有提供一个外部的 etcd 服务的话,也会为 etcd 生成一份额外的静态 Pod 清单文件

静态 Pod 的清单文件被写入到 /etc/kubernetes/manifests 目录; kubelet 会监视这个目录以便在系统启动的时候创建 Pod。

一旦控制平面的 Pod 都运行起来,kubeadm init 的工作流程就继续往下执行。

5.对控制平面节点应用标签和污点标记以便不会在它上面运行其它的工作负载。

6.生成令牌,将来其他节点可使用该令牌向控制平面注册自己。如 kubeadm token 文档所述,用户可以选择通过 --token 提供令牌。

7.为了使得节点能够遵照启动引导令牌和 TLS 启动引导 这两份文档中描述的机制加入到集群中,kubeadm 会执行所有的必要配置:

  • 创建一个 ConfigMap 提供添加集群节点所需的信息,并为该 ConfigMap 设置相关的 RBAC 访问规则。
  • 允许启动引导令牌访问 CSR 签名 API。
  • 配置自动签发新的 CSR 请求。

更多相关信息,请查看 kubeadm join。

8.通过 API 服务器安装一个 DNS 服务器 (CoreDNS) 和 kube-proxy 附加组件。 在 Kubernetes v1.11 和更高版本中,CoreDNS 是默认的 DNS 服务器。 请注意,尽管已部署 DNS 服务器,但直到安装 CNI 时才调度它。

警告

从 v1.18 开始,在 kubeadm 中使用 kube-dns 的支持已被废弃,并已在 v1.21 版本中移除。

拷贝 kubeconfig 文件​

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

添加node节点到集群​

kubeadm join 官方文档

使用ansible执行
ansible node -b -m shell -a "kubeadm join 10.0.0.20:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:8d29b6eba645f3f041d3e9984ac75b3e800aaad60a3d61aada4914559bfe032b"
kubeadm join 10.0.0.10:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:dafdfc22fd8670bb77c258232448fbd937fba9ed40428d5d5319a6acdc2c8e96

在node节点执行 kubeadm join 输出如下

[preflight] Running pre-flight checks
[preflight] Reading configuration from the "kubeadm-config" ConfigMap in namespace "kube-system"...
[preflight] Use 'kubeadm init phase upload-config --config your-config-file' to re-upload it.
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-check] Waiting for a healthy kubelet at http://127.0.0.1:10248/healthz. This can take up to 4m0s
[kubelet-check] The kubelet is healthy after 502.369018ms
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

查看token​

说明

默认情况下,令牌会在 24 小时后过期。如果要在当前令牌过期后将节点加入集群, 则可以通过在控制平面节点上运行以下命令来创建新令牌:

kubeadm token create
$ kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
abcdef.0123456789abcdef 3h 2025-08-13T20:04:44Z authentication,signing <none> system:bootstrappers:kubeadm:default-node-token

查看sha256​

$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
976dee883d1f3cd7b65dee012e0f2b6a42f451f852cf5e7ce1ac6053a7a5f3df

同时查看token和sha256​

注意

执行此命令会重新创建一个token

$ kubeadm token create --print-join-command
kubeadm join 10.0.0.10:6443 --token knn1yv.a0qmgazqdo3mpgb2 --discovery-token-ca-cert-hash sha256:70bd8cbebb1209e556866de47a97a627dfb8fac3a7821702bcb48ebeffffb78c

如果想要在master节点上进行调度pod,例如单机 Kubernetes 集群,应该运行如下命令

kubectl taint nodes --all node-role.kubernetes.io/control-plane-

安装网络插件​

官方文档

可以在这里查看k8s 支持的网络插件

注意

你必须部署一个基于 Pod 网络插件的 容器网络接口 (CNI),以便你的 Pod 可以相互通信。 在安装网络之前,集群 DNS (CoreDNS) 将不会启动。

$ kubectl get po -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-7b5944fdcf-dxw2r 0/1 Pending 0 10m
kube-system coredns-7b5944fdcf-pdlqb 0/1 Pending 0 10m
kube-system etcd-k8s-master01 1/1 Running 1 10m
kube-system kube-apiserver-k8s-master01 1/1 Running 1 10m
kube-system kube-controller-manager-k8s-master01 1/1 Running 1 10m
kube-system kube-proxy-9bzcn 1/1 Running 0 7m32s
kube-system kube-proxy-f98fd 1/1 Running 0 10m
kube-system kube-proxy-kpbt7 1/1 Running 0 7m36s
kube-system kube-proxy-r2bf7 1/1 Running 0 7m31s
kube-system kube-scheduler-k8s-master01 1/1 Running 1 10m
  • 注意你的 Pod 网络不得与任何主机网络重叠: 如果有重叠,你很可能会遇到问题。 (如果你发现网络插件的首选 Pod 网络与某些主机网络之间存在冲突, 则应考虑使用一个合适的 CIDR 块来代替, 然后在执行 kubeadm init 时使用 --pod-network-cidr 参数并在你的网络插件的 YAML 中替换它)。

  • 默认情况下,kubeadm 将集群设置为使用和强制使用 RBAC(基于角色的访问控制)。 确保你的 Pod 网络插件支持 RBAC,以及用于部署它的清单也是如此。

  • 如果要为集群使用 IPv6(双协议栈或仅单协议栈 IPv6 网络), 请确保你的 Pod 网络插件支持 IPv6。 IPv6 支持已在 CNI v0.6.0 版本中添加。

flannel​

flannnel github

calico​

calico github

calico官网

安装calico tigera-operator和自定义资源​
注意

在部署资源的时候,使用 kubectl apply 可能会报错如下,解决方法就是使用 kubectl create,可以查看这个 issues

The CustomResourceDefinition "installations.operator.tigera.io" is invalid: metadata.annotations: Too long: must have at most 262144 bytes

会在 tigera-operator 命名空间下创建资源

export CALICO_VERSION=3.30.2
wget https://raw.githubusercontent.com/projectcalico/calico/v$CALICO_VERSION/manifests/tigera-operator.yaml
kubectl create -f tigera-operator.yaml
安装calico​
注意

custom-resources.yaml 文件中的pod网段默认是 192.168.0.0/16 ,如果集群的pod网段不是 192.168.0.0/16 则需要修改

wget https://raw.githubusercontent.com/projectcalico/calico/v$CALICO_VERSION/manifests/custom-resources.yaml

修改pod网段

export CUST_POD_CIDR=10.244.0.0/16
export FILE_POD_CIDR=192.168.0.0/16
sed -i "s#192.168.0.0/16#$CUST_POD_CIDR#" custom-resources.yaml

创建资源

kubectl apply -f custom-resources.yaml

完成安装​

查看所有pod状态

$ kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
calico-apiserver calico-apiserver-7647545445-2t5s8 1/1 Running 0 104s
calico-apiserver calico-apiserver-7647545445-j7bq7 1/1 Running 0 104s
calico-system calico-kube-controllers-594f57d65d-2n56s 1/1 Running 0 9m21s
calico-system calico-node-2xcgw 1/1 Running 0 9m21s
calico-system calico-node-46kn6 1/1 Running 0 9m21s
calico-system calico-node-fmk4z 1/1 Running 0 9m21s
calico-system calico-node-mhmhj 1/1 Running 0 9m21s
calico-system calico-typha-74f979894f-57bkn 1/1 Running 0 9m19s
calico-system calico-typha-74f979894f-5llqq 1/1 Running 0 9m21s
calico-system csi-node-driver-jt88w 2/2 Running 0 9m21s
calico-system csi-node-driver-m9zqr 2/2 Running 0 9m21s
calico-system csi-node-driver-qhd55 2/2 Running 0 9m21s
calico-system csi-node-driver-s5w4r 2/2 Running 0 9m21s
kube-system coredns-7b5944fdcf-dxw2r 1/1 Running 0 29m
kube-system coredns-7b5944fdcf-pdlqb 1/1 Running 0 29m
kube-system etcd-k8s-master01 1/1 Running 1 29m
kube-system kube-apiserver-k8s-master01 1/1 Running 1 29m
kube-system kube-controller-manager-k8s-master01 1/1 Running 1 29m
kube-system kube-proxy-9bzcn 1/1 Running 0 26m
kube-system kube-proxy-f98fd 1/1 Running 0 29m
kube-system kube-proxy-kpbt7 1/1 Running 0 26m
kube-system kube-proxy-r2bf7 1/1 Running 0 26m
kube-system kube-scheduler-k8s-master01 1/1 Running 1 29m
tigera-operator tigera-operator-76ff79f7fd-spclf 1/1 Running 0 12m

安装完网络插件后,当所有pod都为 running 状态后,集群所有节点状态才为 Ready

$ kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready control-plane 95m v1.33.3
k8s-node01 Ready <none> 94m v1.33.3
k8s-node02 Ready <none> 94m v1.33.3
k8s-node03 Ready <none> 94m v1.33.3
🛡️本站已安全运行2295天22时43分50秒
Bottom GIF
Top GIF